<template>
  <div class="excel-compare">
    <div class="card">
      <div class="card-header">
        <h2>Excel对比工具</h2>
        <p class="description">上传两个Excel文件进行对比，查看它们之间的差异</p>
      </div>
      
      <div class="upload-section">
        <div class="upload-row">
          <div class="file-upload"
               @drop.prevent="handleDropA"
               @dragover.prevent="handleDragOver"
               @dragleave.prevent="handleDragLeave">
            <input 
              type="file" 
              id="fileA" 
              @change="handleFileChangeA"
              class="file-input"
              accept=".xlsx,.xls"
            >
            <label for="fileA" class="upload-button">选择文件A</label>
            <div class="drag-tip">或将文件拖到此处</div>
            <div class="file-name" v-if="fileA">
              已选择: {{ fileA.name }}
            </div>
          </div>
          
          <div class="file-upload"
               @drop.prevent="handleDropB"
               @dragover.prevent="handleDragOver"
               @dragleave.prevent="handleDragLeave">
            <input 
              type="file" 
              id="fileB" 
              @change="handleFileChangeB"
              class="file-input"
              accept=".xlsx,.xls"
            >
            <label for="fileB" class="upload-button">选择文件B</label>
            <div class="drag-tip">或将文件拖到此处</div>
            <div class="file-name" v-if="fileB">
              已选择: {{ fileB.name }}
            </div>
          </div>
        </div>
        
        <div class="compare-section" v-if="fileA && fileB">
          <button 
            class="compare-btn" 
            @click="handleCompare"
            :disabled="isComparing"
          >
            {{ isComparing ? '对比中...' : '开始对比' }}
          </button>
        </div>
      </div>
      
      <div class="result-section" v-if="showResults">
        <div class="diff-summary">
          <h3>对比结果摘要</h3>
          <div class="diff-info">
            <div class="info-item">
              <span class="label">文件A行数:</span>
              <span class="value">{{ fileARows }}</span>
            </div>
            <div class="info-item">
              <span class="label">文件B行数:</span>
              <span class="value">{{ fileBRows }}</span>
            </div>
            <div class="info-item">
              <span class="label">文件A列数:</span>
              <span class="value">{{ fileACols }}</span>
            </div>
            <div class="info-item">
              <span class="label">文件B列数:</span>
              <span class="value">{{ fileBCols }}</span>
            </div>
          </div>
        </div>
        
        <div class="diff-details">
          <h3>列对比结果</h3>
          <div class="diff-list">
            <div 
              v-for="(item, index) in diffResults" 
              :key="index"
              class="diff-item"
              :class="{'diff-match': item.status === 'match', 'diff-mismatch': item.status === 'mismatch', 'diff-missing': item.status === 'missing'}"
            >
              <span class="column-name">{{ item.column }}</span>
              <span class="status-text">{{ getStatusText(item.status) }}</span>
              <span class="detail-text" v-if="item.detail">{{ item.detail }}</span>
            </div>
          </div>
        </div>
        
        <div class="excel-preview-container">
          <div class="excel-preview">
            <h3>文件A预览</h3>
            <div class="table-container">
              <table v-if="fileAData.length">
                <thead>
                  <tr>
                    <th v-for="(header, index) in fileAHeaders" :key="index">{{ header }}</th>
                  </tr>
                </thead>
                <tbody>
                  <tr v-for="(row, rowIndex) in fileAData.slice(0, 10)" :key="rowIndex">
                    <td v-for="(cell, cellIndex) in row" :key="cellIndex">{{ cell }}</td>
                  </tr>
                </tbody>
              </table>
              <div class="no-data" v-else>无数据预览</div>
            </div>
          </div>
          
          <div class="excel-preview">
            <h3>文件B预览</h3>
            <div class="table-container">
              <table v-if="fileBData.length">
                <thead>
                  <tr>
                    <th v-for="(header, index) in fileBHeaders" :key="index">{{ header }}</th>
                  </tr>
                </thead>
                <tbody>
                  <tr v-for="(row, rowIndex) in fileBData.slice(0, 10)" :key="rowIndex">
                    <td v-for="(cell, cellIndex) in row" :key="cellIndex">{{ cell }}</td>
                  </tr>
                </tbody>
              </table>
              <div class="no-data" v-else>无数据预览</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import * as XLSX from 'xlsx'

// 文件状态
const fileA = ref<File | null>(null)
const fileB = ref<File | null>(null)
const isComparing = ref(false)
const showResults = ref(false)

// 数据状态
const fileAData = ref<any[][]>([])
const fileBData = ref<any[][]>([])
const fileAHeaders = ref<string[]>([])
const fileBHeaders = ref<string[]>([])
const fileARows = ref(0)
const fileBRows = ref(0)
const fileACols = ref(0)
const fileBCols = ref(0)

// 对比结果
const diffResults = ref<Array<{column: string, status: 'match' | 'mismatch' | 'missing', detail?: string}>>([])

// 文件A上传处理
const handleFileChangeA = (event: Event) => {
  const input = event.target as HTMLInputElement
  const file = input.files?.[0]
  if (!file) return
  
  // 检查文件类型
  if (!file.name.endsWith('.xlsx') && !file.name.endsWith('.xls')) {
    ElMessage.error('请上传Excel文件(.xlsx或.xls)')
    return
  }
  
  fileA.value = file
  showResults.value = false
}

// 文件B上传处理
const handleFileChangeB = (event: Event) => {
  const input = event.target as HTMLInputElement
  const file = input.files?.[0]
  if (!file) return
  
  // 检查文件类型
  if (!file.name.endsWith('.xlsx') && !file.name.endsWith('.xls')) {
    ElMessage.error('请上传Excel文件(.xlsx或.xls)')
    return
  }
  
  fileB.value = file
  showResults.value = false
}

// 拖拽处理
const handleDragOver = (event: DragEvent) => {
  event.target && (event.target as HTMLElement).closest('.file-upload')?.classList.add('dragover')
}

const handleDragLeave = (event: DragEvent) => {
  event.target && (event.target as HTMLElement).closest('.file-upload')?.classList.remove('dragover')
}

const handleDropA = (event: DragEvent) => {
  event.target && (event.target as HTMLElement).closest('.file-upload')?.classList.remove('dragover')
  const file = event.dataTransfer?.files[0]
  
  if (!file) return
  
  // 检查文件类型
  if (!file.name.endsWith('.xlsx') && !file.name.endsWith('.xls')) {
    ElMessage.error('请上传Excel文件(.xlsx或.xls)')
    return
  }
  
  // 创建一个新的 FileList 对象
  const dataTransfer = new DataTransfer()
  dataTransfer.items.add(file)
  
  // 更新 input 的文件
  const fileInput = document.getElementById('fileA') as HTMLInputElement
  if (fileInput) {
    fileInput.files = dataTransfer.files
    fileA.value = file
    showResults.value = false
  }
}

const handleDropB = (event: DragEvent) => {
  event.target && (event.target as HTMLElement).closest('.file-upload')?.classList.remove('dragover')
  const file = event.dataTransfer?.files[0]
  
  if (!file) return
  
  // 检查文件类型
  if (!file.name.endsWith('.xlsx') && !file.name.endsWith('.xls')) {
    ElMessage.error('请上传Excel文件(.xlsx或.xls)')
    return
  }
  
  // 创建一个新的 FileList 对象
  const dataTransfer = new DataTransfer()
  dataTransfer.items.add(file)
  
  // 更新 input 的文件
  const fileInput = document.getElementById('fileB') as HTMLInputElement
  if (fileInput) {
    fileInput.files = dataTransfer.files
    fileB.value = file
    showResults.value = false
  }
}

// 读取Excel文件
const readExcelFile = (file: File): Promise<{data: any[][], headers: string[]}> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    
    reader.onload = (e) => {
      try {
        const data = e.target?.result
        const workbook = XLSX.read(data, { type: 'array' })
        const firstSheetName = workbook.SheetNames[0]
        const worksheet = workbook.Sheets[firstSheetName]
        
        // 转换为数组
        const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 }) as any[][]
        
        // 提取表头
        const headers = jsonData[0].map(String)
        
        resolve({
          data: jsonData.slice(1), // 数据行（不包括表头）
          headers // 表头
        })
      } catch (error) {
        reject(error)
      }
    }
    
    reader.onerror = (error) => {
      reject(error)
    }
    
    reader.readAsArrayBuffer(file)
  })
}

// 对比Excel文件
const handleCompare = async () => {
  if (!fileA.value || !fileB.value) {
    ElMessage.warning('请先上传两个Excel文件')
    return
  }
  
  isComparing.value = true
  diffResults.value = []
  
  try {
    // 读取两个文件
    const fileAResult = await readExcelFile(fileA.value)
    const fileBResult = await readExcelFile(fileB.value)
    
    // 更新数据
    fileAData.value = fileAResult.data
    fileBData.value = fileBResult.data
    fileAHeaders.value = fileAResult.headers
    fileBHeaders.value = fileBResult.headers
    
    // 更新行列统计
    fileARows.value = fileAResult.data.length
    fileBRows.value = fileBResult.data.length
    fileACols.value = fileAResult.headers.length
    fileBCols.value = fileBResult.headers.length
    
    // 对比列
    compareColumns(fileAResult.headers, fileBResult.headers)
    
    showResults.value = true
    ElMessage.success('对比完成')
  } catch (error) {
    console.error('对比失败:', error)
    ElMessage.error('对比失败，请检查文件格式是否正确')
  } finally {
    isComparing.value = false
  }
}

// 对比列
const compareColumns = (headersA: string[], headersB: string[]) => {
  // 清空之前的结果
  diffResults.value = []
  
  // 遍历文件A的所有列
  headersA.forEach((columnA, index) => {
    // 在文件B中查找相同名称的列
    const indexInB = headersB.findIndex(columnB => columnB === columnA)
    
    if (indexInB === -1) {
      // 文件B中不存在该列
      diffResults.value.push({
        column: columnA,
        status: 'missing',
        detail: '在文件B中不存在'
      })
    } else {
      // 文件B中存在该列，对比数据
      const isMatch = compareColumnData(index, indexInB)
      diffResults.value.push({
        column: columnA,
        status: isMatch ? 'match' : 'mismatch',
        detail: isMatch ? undefined : '数据不一致'
      })
    }
  })
  
  // 查找文件B中存在但文件A中不存在的列
  headersB.forEach(columnB => {
    if (!headersA.includes(columnB)) {
      diffResults.value.push({
        column: columnB,
        status: 'missing',
        detail: '在文件A中不存在'
      })
    }
  })
  
  // 按列名排序
  diffResults.value.sort((a, b) => a.column.localeCompare(b.column))
}

// 对比列数据
const compareColumnData = (columnIndexA: number, columnIndexB: number): boolean => {
  // 如果行数不同，直接认为不一致
  if (fileAData.value.length !== fileBData.value.length) {
    return false
  }
  
  // 逐行对比
  for (let i = 0; i < fileAData.value.length; i++) {
    const rowA = fileAData.value[i]
    const rowB = fileBData.value[i]
    
    // 如果某一行的该列数据不同，则认为不一致
    if (String(rowA[columnIndexA]) !== String(rowB[columnIndexB])) {
      return false
    }
  }
  
  return true
}

// 获取状态文本
const getStatusText = (status: string): string => {
  switch (status) {
    case 'match':
      return '一致'
    case 'mismatch':
      return '不一致'
    case 'missing':
      return '缺失'
    default:
      return ''
  }
}
</script>

<style scoped>
.excel-compare {
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
}

.card {
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.06);
  padding: 24px;
}

.card-header {
  margin-bottom: 24px;
  text-align: center;
}

.card-header h2 {
  margin: 0;
  font-size: 24px;
  color: #2d3748;
  font-weight: 600;
}

.description {
  color: #64748b;
  margin-top: 8px;
}

.upload-section {
  width: 100%;
  margin: 20px 0;
}

.upload-row {
  display: flex;
  gap: 20px;
  margin-bottom: 20px;
}

@media (max-width: 768px) {
  .upload-row {
    flex-direction: column;
  }
}

.file-upload {
  position: relative;
  display: block;
  padding: 30px;
  border: 2px dashed #e2e8f0;
  border-radius: 8px;
  background: #f8fafc;
  transition: all 0.3s ease;
  text-align: center;
  flex: 1;
}

.file-upload.dragover {
  border-color: #4f46e5;
  background: #eef2ff;
}

.file-input {
  position: absolute;
  width: 0;
  height: 0;
  opacity: 0;
}

.upload-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 24px;
  background: #4f46e5;
  color: white;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-weight: 500;
  width: 80%;
  max-width: 200px;
  font-size: 16px;
}

.upload-button:hover {
  background: #4338ca;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(79, 70, 229, 0.2);
}

.drag-tip {
  margin-top: 10px;
  color: #64748b;
  font-size: 14px;
}

.file-name {
  margin-top: 15px;
  color: #4f46e5;
  font-size: 14px;
  font-weight: 500;
}

.compare-section {
  margin-top: 24px;
  text-align: center;
}

.compare-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 36px;
  background: #4f46e5;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-weight: 500;
  font-size: 16px;
}

.compare-btn:hover {
  background: #4338ca;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(79, 70, 229, 0.2);
}

.compare-btn:disabled {
  background: #a5b4fc;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.result-section {
  margin-top: 30px;
}

.diff-summary {
  background: #f8fafc;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 20px;
}

.diff-summary h3 {
  margin-top: 0;
  margin-bottom: 12px;
  font-size: 18px;
  color: #2d3748;
}

.diff-info {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.info-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.label {
  font-weight: 500;
  color: #4b5563;
}

.value {
  color: #1f2937;
  font-weight: 600;
}

.diff-details {
  background: #f8fafc;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 20px;
}

.diff-details h3 {
  margin-top: 0;
  margin-bottom: 12px;
  font-size: 18px;
  color: #2d3748;
}

.diff-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.diff-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  border-radius: 6px;
  background: white;
}

.diff-match {
  border-left: 4px solid #10b981;
}

.diff-mismatch {
  border-left: 4px solid #ef4444;
}

.diff-missing {
  border-left: 4px solid #f59e0b;
}

.column-name {
  font-weight: 500;
  min-width: 120px;
}

.status-text {
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 14px;
  font-weight: 500;
}

.diff-match .status-text {
  background: #d1fae5;
  color: #065f46;
}

.diff-mismatch .status-text {
  background: #fee2e2;
  color: #b91c1c;
}

.diff-missing .status-text {
  background: #fef3c7;
  color: #92400e;
}

.detail-text {
  color: #6b7280;
  font-size: 14px;
}

.excel-preview-container {
  display: flex;
  gap: 20px;
  margin-top: 20px;
}

@media (max-width: 992px) {
  .excel-preview-container {
    flex-direction: column;
  }
}

.excel-preview {
  flex: 1;
  background: #f8fafc;
  border-radius: 8px;
  padding: 16px;
}

.excel-preview h3 {
  margin-top: 0;
  margin-bottom: 12px;
  font-size: 18px;
  color: #2d3748;
}

.table-container {
  overflow-x: auto;
  max-height: 400px;
  overflow-y: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}

th, td {
  padding: 8px 12px;
  text-align: left;
  border-bottom: 1px solid #e5e7eb;
}

th {
  background: #f1f5f9;
  font-weight: 600;
  color: #4b5563;
  position: sticky;
  top: 0;
  z-index: 1;
}

tr:nth-child(even) {
  background: #f9fafb;
}

.no-data {
  padding: 40px;
  text-align: center;
  color: #6b7280;
}
</style> 